/*->c.dc     */

/* Ovation!   (c) D. J. Pilling,  December 1988                     */
/*                        Dictionary Code                             */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <signal.h>
#include <ctype.h>
#include <time.h>

#include "h.os"
#include "h.wimp"
#include "h.sprite"
#include "h.font"
#include "h.bbc"


#include "h.def"

#include "h.wos"

#include "h.vm"

#include "h.dc"



/*****************************************************************************/

#define OLDVERSION


#ifdef OLDVERSION

char * mfx[256]=
{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"abilities", /* 31 */
"ability",
"phobia",
"ities",
"body",
"naut",
"olog",
"able",
"'",        /* ' 39 */
"ally",
"ance",
"edge",
"ance",
"ancy",
"-",        /* - 45 */
"ence",
"ency",
"0",        /* 0 48 */
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",         /* 9 57 */
"hood",
"less",
"like",
"logy",
"ment",
"ness",
"ophy",
"A",         /* A 65 */
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"ship",
"tion",
"ace",
"act",
"age",
"ane",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",       /* z 122 */
"ant",
"ate",
"ent",
"ess",
"ful",
"ian",
"ies",
"ine",
"ing",
"ion",
"ise",
"ish",
"ism",
"ite",
"ity",
"ium",
"ive",
"ize",
"man",
"oid",
"ome",
"ous",
"tic",
"tum",
"ure",
"way",
"al",
"am",
"an",
"ar",
"ch",
"ck",
"de",
"ea",
"ed",
"ee",
"en",
"er",
"es",
"ey",
"gh",
"ic",
"ie",
"in",
"is",
"it",
"le",
"ll",
"ly",
"nd",
"ne",
"nn",
"nt",
"on",
"oo",
"or",
"ph",
"re",
"ry",
"se",
"sh",
"ss",
"te",
"th",
"tt",
"ty",
"um",
"un",
"us",
"",   /* 192 */
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
""};


#else


char * mfx[256]=
{
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"ng",
"ss",
"ess",
"on",
"er",
"ed",
"le",
"ion",
"'",
"te",
"ble",
"al",
"es",
"ce",
"-",
"nt",
"us",
"0",
"1",
"2",
"3",
"4",
"5",
"6",
"7",
"8",
"9",
"tion",
"an",
"ate",
"ic",
"ty",
"ent",
"ies",
"A",
"B",
"C",
"D",
"E",
"F",
"G",
"H",
"I",
"J",
"K",
"L",
"M",
"N",
"O",
"P",
"Q",
"R",
"S",
"T",
"U",
"V",
"W",
"X",
"Y",
"Z",
"se",
"able",
"ne",
"ation",
"re",
"nce",
"a",
"b",
"c",
"d",
"e",
"f",
"g",
"h",
"i",
"j",
"k",
"l",
"m",
"n",
"o",
"p",
"q",
"r",
"s",
"t",
"u",
"v",
"w",
"x",
"y",
"z",
"st",
"ing",
"ous",
"ge",
"de",
"ly",
"nd",
"ity",
"rd",
"ck",
"sm",
"ry",
"sh",
"en",
"ar",
"ia",
"in",
"ter",
"ul",
"ted",
"lity",
"ch",
"ility",
"bility",
"ard",
"lly",
"ence",
"is",
"et",
"ve",
"um",
"ct",
"ance",
"me",
"ine",
"ht",
"ay",
"tic",
"ad",
"ll",
"ian",
"ip",
"cal",
"ght",
"el",
"and",
"ries",
"ication",
"ant",
"cy",
"age",
"at",
"th",
"ial",
"ious",
"id",
"ke",
"ire",
"one",
"ish",
"ive",
"logy",
"ness",
"ogical",
"il",
"own",
"ties",
"it",
"ue",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
"",
};


#endif


#define NMIDFIX sizeof(mfx) / sizeof(char *)


/*****************************************************************************/


/* make a change to the word string space */

void changeword(dict * dp,char * code,int woffset,int newlen,int oldlen)
{
 int    n;
 char * c;
 int    i;
 n=alterbuffer(dp->words,woffset,newlen-oldlen);
 formblock(dp->words,0,SIZEBUFF(dp->words));
 c=charbuffer(dp->words,woffset);
 for(i=0;i<newlen;i++) *c++=code[i];
}


/* insert a new index pointer at indexn */

index * insindex(dict * dp,int indexn)
{
 alterbuffer(dp->index,indexn*sizeof(index),sizeof(index));
 formblock(dp->index,0,SIZEBUFF(dp->index));
 dp->noindex++;
 return((index *)charbuffer(dp->index,indexn*sizeof(index)));
}


void delindex(dict * dp,int indexn)
{
 alterbuffer(dp->index,indexn*sizeof(index),-sizeof(index));
 formblock(dp->index,0,SIZEBUFF(dp->index));
 dp->noindex--;
}


#define SPLIT 12

int lolim[SPLIT]={31,40,46,58,91,123,39,45,48,65,97 ,192};
int hilim[SPLIT]={39,45,49,65,97,192,40,46,58,91,123,256};

int codeword(char * prev,char * word,char *  code)
{
 int i=0;
 int j,k,l;
 int w=0;

 while(prev[i] && word[i] && prev[i]==word[i]) i++;

 *(code+w)=i;
 w++;
 if(!word[i]) return(w);

 word+=i;

 while(1)
 {
  if(w>=STRLEN) return(0);

  for(l=0;l<SPLIT;l++)                   /* looking for end of word */
  {
   for(j=lolim[l];j<hilim[l];j++)
   {
    if(!strcmp(word,mfx[j]))
    {
     *(code+w)=j;
     w++;
     return(w);
    }
   }
  }

  for(l=0;l<SPLIT;l++)                   /* looking for mid strings */
  {
   for(j=lolim[l];j<hilim[l];j++)
   {
    k=0;
    while(mfx[j][k])
     {
      if(mfx[j][k]!=word[k]) break; 
      else                   k++;
     }
    if(!mfx[j][k] && word[k]) break;
   }
   if(j<hilim[l]) break;
  }

  if(l==SPLIT) return(0);

  *(code+w)=j;
  w++;
  word+=k;
 }
}



int formword(dict * dp,word * words)
{
 char * c;
 int    n;

 c=charbuffer(dp->words,words->woffset);
 n=(*c) & 0x1F;
 words->string[n]=0;

 n=0;
 while(1)
 {
  c++;
  n++;
  if((*c)<MINTOK) break;
  strcat(words->string,mfx[*c]);
 }

 words->len=n;
 return(1);
}




/* given one words structure, step to the next one */
/* return 0 if no more                             */

int nextword(dict * dp,word * words)
{
 char * c;
 int    n;
 int    offset;

 words->woffset+=words->len;

 words->wordn++;
 if(words->wordn>=dp->nowords)
 {
  words->len=0;
  strcpy(words->string,"");
  return(0);
 }

 offset=words->woffset;

 c=charbuffer(dp->words,offset);
 n=(*c) & 0x1F;
 words->string[n]=0;

 n=0;
 while(1)
 {
/*  offset++;
  c=charbuffer(dp->words,offset);  */
  c++;
  n++;
  if((*c)<MINTOK) break;
  strcat(words->string,mfx[*c]);
 }

 words->len=n;

 return(1);
}


/***************************************************************************/

/*

void printindexs(dict *dp)
{
 int     indexn;
 index * indexp;
 char    string[16];

 for(indexn=dp->noindex-1;indexn<dp->noindex;indexn++)
 {
  indexp=(index*)charbuffer(dp->index,indexn*sizeof(index));

  strncpy(string,indexp->key,KEYLEN);
  string[KEYLEN+1]=0;
 }

}


 */


/* check if index is OK, return 1, else remove index and return 0 */

int validindex(dict * dp,int indexn,word * words)
{
 int    maxwordn;
 int    change=0;
 char * c;
 int    n;

 index * indexp=(index*)charbuffer(dp->index,indexn*sizeof(index));


/*  dprintf(1,"validindex enter ");   */


 if((indexn+1)<dp->noindex) 
     maxwordn=WORDN((index*)charbuffer(dp->index,(indexn+1)*sizeof(index)));
 else
     maxwordn=dp->nowords;

 while((words->wordn)<maxwordn)
 {
  c=charbuffer(dp->words,words->woffset);
  n=(*c) & 0x1F;
  if(n<KEYLEN) break;
  change=1;
  nextword(dp,words);
 }

/* dprintf(1,"validindex change=%d",change); */


 if(n<KEYLEN && change)
 {
  SETWORDN(indexp,words->wordn);
  SETWOFF(indexp,words->woffset);
  strncpy(indexp->key,words->string,KEYLEN);
  return(1);
 }
 else
 if(change)
 {
  delindex(dp,indexn);
  return(0);
 }

 return(1);
}



void setindx(int index1,index ** indexp0,index ** indexp1,index ** indexp2,
                                                                dict * dp)
{
 int index0;
 int index2;

 index0=index1-1;
 index2=index1+1;

 if(index0>=0) *indexp0=(index *)charbuffer(dp->index,index0*sizeof(index));
 else          *indexp0=NULL;

 *indexp1=(index *)charbuffer(dp->index,index1*sizeof(index));

 if(index2<dp->noindex) 
               *indexp2=(index *)charbuffer(dp->index,index2*sizeof(index));
 else          *indexp2=NULL;

}


/* given words structure, remove from dictionary */

int remword(dict * dp,word * words)
{
 word    nextwords;
 word    prevwords;

 int     index0;
 int     index1;
 int     index2;

 index * indexp0;
 index * indexp1;
 index * indexp2;

 char    code[STRLEN];
 int     shift;
 int     indexn;
 int     indexc;
 index * indexp;
 index * f;

 int     tempwoffset;
 int     tempwordn;
 int     len;
 int     maxindex=dp->noindex;

 int     delcurindex=0;
 int     nextindex=0;
 int     curvalid=1;

 int     wn;


 /* accepting that due to error in findword, may get index one too small */

 while(1)
 {
  index1=words->indexn;
  index1++;
  if(index1>=maxindex) break;
  indexp1=(index *)charbuffer(dp->index,index1*sizeof(index));
  if(words->wordn<WORDN(indexp1)) break;
  words->indexn=words->indexn+1;
 }

 index1=words->indexn;
 index0=index1-1;
 index2=index1+1;


 setindx(index1,&indexp0,&indexp1,&indexp2,dp);

 if(dp->nowords==1)    /* only one word in dictionary */
 {
  setsizebuffer(&dp->words,0);
  setsizebuffer(&dp->index,0);
  dp->nowords=0;
  dp->noindex=0;
 }
 else
 if(words->wordn==(dp->nowords-1))  /* deleting last word */
 {
  if(words->wordn==WORDN(indexp1)) delindex(dp,index1);
  changeword(dp,NULL,words->woffset,0,words->len);
  dp->nowords--;
 }
 else
 if(!words->wordn)                  /* deleting first word */
 {
  nextwords=*words;
  nextword(dp,&nextwords);
  len=codeword("",nextwords.string,code);
  strncpy(indexp1->key,nextwords.string,KEYLEN);
  shift=len-words->len-nextwords.len;
  changeword(dp,code,words->woffset,len,words->len+nextwords.len);
  dp->nowords--;

  indexn=index1;
  indexc=indexn*sizeof(index);
  while(++indexn<maxindex)
  {
   indexc+=sizeof(index);
   indexp=(index *)charbuffer(dp->index,indexc);
   tempwoffset=WOFF(indexp)+shift;
   tempwordn=WORDN(indexp)-1;
   SETWORDN(indexp,tempwordn);
   SETWOFF(indexp,tempwoffset);
  }

 }
 else                              /* deleting word in middle */
 {
  nextwords=*words;
  nextword(dp,&nextwords);

  delcurindex=words->wordn==WORDN(indexp1);
  nextindex=indexp2 && (nextwords.wordn==WORDN(indexp2));

/*
  dprintf(0,"delcurindex=%d nextindex=%d",delcurindex,nextindex); 
  dprintf(1,"wordn=%d WORDN=%d string=%s",words->wordn,WORDN(indexp1),
                                        words->string);
*/

  if(words->wordn>WORDN(indexp1))
  {
   f=indexp1;
   prevwords.indexn=index1;
  }
  else
  {
   f=indexp0;
   prevwords.indexn=index0;
  }

  strncpy(prevwords.string,f->key,KEYLEN);
  prevwords.woffset=WOFF(f);
  prevwords.wordn=WORDN(f);
  prevwords.len=0;

  formword(dp,&prevwords);

  while(prevwords.wordn<(words->wordn-1)) nextword(dp,&prevwords);

 /* dprintf(2,"prev=%s next=%s",prevwords.string,nextwords.string); */

  len=codeword(prevwords.string,nextwords.string,code);
  nextwords.woffset-=words->len;
  nextwords.wordn-=1;
  shift=len-words->len-nextwords.len;
  changeword(dp,code,words->woffset,len,words->len+nextwords.len);
  nextwords.len=len;
  dp->nowords--;

  setindx(index1,&indexp0,&indexp1,&indexp2,dp);

  if(delcurindex)
  {
   strncpy(indexp1->key,nextwords.string,KEYLEN);
  }

  if(nextindex)
  {
   tempwoffset=WOFF(indexp2)-words->len;
   tempwordn=WORDN(indexp2)-1;
   SETWORDN(indexp2,tempwordn);
   SETWOFF(indexp2,tempwoffset);
   indexn=index2;
  }
  else
  {
   indexn=index1;
  }

  indexc=indexn*sizeof(index);
  while(++indexn<maxindex)
  {
   indexc+=sizeof(index);
   indexp=(index *)charbuffer(dp->index,indexc);
   tempwoffset=WOFF(indexp)+shift;
   tempwordn=WORDN(indexp)-1;
   SETWORDN(indexp,tempwordn);
   SETWOFF(indexp,tempwoffset);
  }

  if(delcurindex) curvalid=validindex(dp,index1,&nextwords);
 }


 if(dp->nowords && curvalid && dp->noindex>1 && index1>0)
 {
  /* merge indexes */
  /* we know word has been chopped out of index1 */

  setindx(index1,&indexp0,&indexp1,&indexp2,dp);
 
  wn=WORDN(indexp1)-WORDN(indexp0);
  if(wn<64) 
  {
   delindex(dp,index1);
  }
  else
  if(index2<dp->noindex)
  {
   wn=WORDN(indexp2)-WORDN(indexp1);
   if(wn<64) delindex(dp,index1);
  }
  else
  {
   wn=dp->nowords-WORDN(indexp1);
   if(wn<64) delindex(dp,index1);
  }

 }

 return(1);
}



void splitindex(dict * dp,int indexn,int count)
{
 word words;
 index * indexp;
 char * c;
 int    n=KEYLEN;                  /* probably needed */
 int    maxwordn;
 int    startn;


 indexp=(index*)charbuffer(dp->index,indexn*sizeof(index));

 strncpy(words.string,indexp->key,KEYLEN);
 words.woffset=WOFF(indexp);
 words.indexn=indexn;
 words.wordn=WORDN(indexp);
 words.len=0;
 formword(dp,&words);


 maxwordn=WORDN(indexp)+count;
 startn=WORDN(indexp)+count/2;

/* dprintf(1,"split index word=%s maxwordn=%d startn=%d",
                                   words.string,maxwordn,startn); */


 while(words.wordn<startn) nextword(dp,&words);

 while(words.wordn<maxwordn)
 {
  c=charbuffer(dp->words,words.woffset);
  n=(*c) & 0x1F;
  if(n<KEYLEN) break;
  nextword(dp,&words);
 }

 if(n<KEYLEN)
 {
  indexp=insindex(dp,indexn+1);
  SETWORDN(indexp,words.wordn);
  SETWOFF(indexp,words.woffset);
  strncpy(indexp->key,words.string,KEYLEN);

 /* dprintf(2,"split index word=%s ",words.string); */
 }

}





/* add words structure to dictionary             */
/* return 1 on OK */

int storeword(char * string,dict * dp,word * words)
{
 char    code[STRLEN];
 int     len;
 int     oldnxlen;
 index * indexp;
 word    nextwords;
 int     isnext;
 int     val;

 int     indexn;
 int     indexbase;
 int     indexc;
 int     maxindex;
 int     shift;

 int     count;

 int     tempwoffset;
 int     tempwordn;

 int     flags=0;

 int     checkvalid=0;
 int     n;
 int     index1;
 index * indexp1;


 maxindex=dp->noindex;

 /* accepting that due to error in findword, may get index one too small */

 while(1)
 {
  index1=words->indexn;
  index1++;
  if(index1>=maxindex) break;
  indexp1=(index *)charbuffer(dp->index,index1*sizeof(index));
  if(words->wordn<WORDN(indexp1)) break;
  words->indexn=words->indexn+1;
 }


 if(!dp->nowords)
 {
  len=codeword("",string,code);
  if(!len) return(0);
  code[len++]=0;
  code[len++]=0;

  n=alterbuffer(dp->words,0,2*STRLEN);
  alterbuffer(dp->words,0,-2*STRLEN);
  if(n<(2*STRLEN)) return(0);

  changeword(dp,code,0,len,0);
  indexp=insindex(dp,0);
  SETWOFF(indexp,0);
  SETWORDN(indexp,0);
  strncpy(indexp->key,string,KEYLEN);
 }
 else
 {
  indexbase=indexn=words->indexn;
  indexc=indexn*sizeof(index);


  val=xstrncmp(string,words->string,STRMAX,&flags);
  nextwords=*words;

  n=alterbuffer(dp->words,nextwords.woffset,2*STRLEN);
  alterbuffer(dp->words,nextwords.woffset,-2*STRLEN);
  if(n<(2*STRLEN)) return(0);


  if(val>0)
  {
   len=codeword(words->string,string,code);
   if(!len) return(0);
   isnext=nextword(dp,&nextwords);
  }
  else
  {                        /* there wasn't a smaller word - so must be first */
   len=codeword("",string,code);
   if(!len) return(0);
   indexp=(index *)charbuffer(dp->index,indexc);
   strncpy(indexp->key,string,KEYLEN);
   isnext=1;
  }

  changeword(dp,code,nextwords.woffset,len,0);
  shift=len;

  if(isnext)
  {
   nextwords.woffset+=len;
   len=codeword(string,nextwords.string,code);
   changeword(dp,code,nextwords.woffset,len,nextwords.len);
   oldnxlen=nextwords.len;
   nextwords.len=len;

  /* dprintf(5,"nextwords->string=%s",nextwords.string); */

   if((indexn+1)<maxindex)
   {
    indexp=(index *)charbuffer(dp->index,indexc+sizeof(index));

  /*  dprintf(4,"WORDN(indexp)=%d word=%d",WORDN(indexp),nextwords.wordn); */

    if(WORDN(indexp)==nextwords.wordn)
    {
     indexn++;
     indexc+=sizeof(index);
     tempwoffset=WOFF(indexp)+shift;
     tempwordn=WORDN(indexp)+1;
     SETWORDN(indexp,tempwordn);
     SETWOFF(indexp,tempwoffset);
     checkvalid=indexn;
/*     indexn++;
     indexc+=sizeof(index);  */  /* because loop below preincrements */
    }
   }
   nextwords.wordn++;
   shift+=len-oldnxlen;
  }


  while(++indexn<maxindex)
  {
   indexc+=sizeof(index);
   indexp=(index *)charbuffer(dp->index,indexc);
   tempwoffset=WOFF(indexp)+shift;
   tempwordn=WORDN(indexp)+1;
   SETWORDN(indexp,tempwordn);
   SETWOFF(indexp,tempwoffset);
  }

  if(checkvalid) validindex(dp,checkvalid,&nextwords);

  indexn=indexbase;
  indexc=indexn*sizeof(index);
  indexp=(index *)charbuffer(dp->index,indexc);
  count=WORDN(indexp);

  if(++indexn<maxindex)
  {
   indexc+=sizeof(index);
   indexp=(index *)charbuffer(dp->index,indexc);
   count=WORDN(indexp)-count;
  }
  else
  {
   count=dp->nowords-count;
  }

  if(count>=128) splitindex(dp,indexbase,count);
 }


 indexp=(index *)charbuffer(dp->index,sizeof(index)*226);
/* dprintf(3,"(226) wordn=%d",WORDN(indexp)); */



 dp->nowords++;
 return(1);
}





/* returns 1 if word found or 0 if not found     */
/* returns previous word structure in dictionary */
/* flags 0x10000 == ignore hyphens               */
/*       0x20000 == fast search return no data   */

int findword(char * string,dict * dp,word * words,int * flags)
{
 int         n=dp->noindex;
 int         lo=0;
 int         hi=(n-1)*sizeof(index);
 int         i=0;
 int         loi=0;
 int         hii=n-1;
 int         ii=0;
 int         code;
 index    *  f;
 char     *  p;
 word        oldwords;

 if(!dp->nowords)
 {
  words->woffset=0;
  words->indexn=0;
  strcpy(words->string,"");
  words->wordn=0;
  words->len=0;
 }
 else
 {
  p=charbuffer(dp->index,0);

  while(hi>=lo)
  {
   i=(lo+hi)>>1;
   ii=loi+hii;
   if((ii & 1) && i) i-=(sizeof(index)>>1);
   ii=ii>>1;

   f=(index *)(p+i);

   code=xstrncmp(string,f->key,KEYLEN,flags);

   if(!code) break;
   else
   if(code>0) {lo=i+sizeof(index);loi=ii+1;}
   else       {hi=i-sizeof(index);hii=ii-1;}
  }

  while((code<=0) && (i>0))
  {
   i-=sizeof(index);
   ii--;
   f=(index *)(p+i);
   code=xstrncmp(string,f->key,KEYLEN,flags);
  }

  if((*flags) & 0x20000)                   /* fast search */
  {
/*   bbc_vdu(4);bbc_vdu(30);bbc_vdu(10); */
   return(xscanword(string,flags,f->key,charbuffer(dp->words,WOFF(f))));
/*   bbc_vdu(5); */

  }
  else  
  {
   strncpy(words->string,f->key,KEYLEN);
   words->woffset=WOFF(f);
   words->indexn=ii;
   words->wordn=WORDN(f);
   words->len=0;

   formword(dp,words);

   oldwords=*words;

   while(1)
   {
    code=xstrncmp(string,words->string,STRMAX,flags);
    if(!code)  return(1);
    if(code<0) break;
    oldwords=*words;
    if(!nextword(dp,words)) break;
   }

   *words=oldwords;
  }
 }
   
 return(0);
}





void testdict(dict * dp)
{
 int         n=dp->noindex;
 index    *  f;
 char     *  p;
 int         i;

 for(i=0;i<n;i++)
 {
  f=(index*)charbuffer(dp->index,i*sizeof(index));
  p=charbuffer(dp->words,WOFF(f));
  if(*p>30)
  {
   dprintf(0,"error index=%d f->key=%s f->woff=%d",i,f->key,WOFF(f));
  }
 }
}





/* returns word structure for n'th word in dictionary */

int locword(int seekn,dict * dp,word * words)
{
 int         n=dp->noindex;
 int         lo=0;
 int         hi=(n-1)*sizeof(index);
 int         i=0;
 int         loi=0;
 int         hii=n-1;
 int         ii=0;
 index    *  f;


 if(seekn>=dp->nowords) return(0);

 while(hi>=lo)
 {
  i=(lo+hi)>>1;
  ii=loi+hii;
  if((ii & 1) && i) i-=sizeof(index)/2;
  ii=ii>>1;

  f=(index *)charbuffer(dp->index,i);

  if(WORDN(f)==seekn) break;
  else
  if(WORDN(f)<seekn)  {lo=i+sizeof(index);loi=ii+1;}
  else                {hi=i-sizeof(index);hii=ii-1;}
 }
        

 if(WORDN(f)>seekn)
 {
  i-=sizeof(index);
  ii--;
  f=(index *)charbuffer(dp->index,i);
 }

 strncpy(words->string,f->key,KEYLEN);
 words->woffset=WOFF(f);
 words->indexn=ii;
 words->wordn=WORDN(f);
 words->len=0;
 formword(dp,words);

 while(words->wordn<seekn) nextword(dp,words);
 return(1);
}


/****************************************************************************/


/* delete a word from a dictionary */

int deleteword(char * string,dict * dp)
{
 word words;
 int  code;
 int  flags=0;

 code=findword(string,dp,&words,&flags);
 if(!code) return(0);             /* word was not in dictionary */
 code=remword(dp,&words);
 return(code);
}


/* add a word to a dictionary */

int addword(char * string,dict * dp)
{
 int  code;
 word words;
 int  flags=0;
 int  len=strlen(string);

 if(!len || len>STRMAX) return(0);

 code=findword(string,dp,&words,&flags);
 if(code)                /* word was in dictionary */
 {
  if(!strncmp(string,words.string,STRMAX)) return(1);
  deleteword(string,dp);
  code=findword(string,dp,&words,&flags);
 }
 code=storeword(string,dp,&words);

 return(code);
}



char * wordn(int n,dict * dp)
{
 static char string[32];
 int         code;
 word        words;
 code=locword(n,dp,&words);
 if(code) strcpy(string,words.string);
 else     strcpy(string,"");
 return(string);
}


int nowords(dict * dp)
{
 return(dp->nowords);
}


/*****************************************************************************/


/* clear dictionary structure */

void trashdc(dict * dp)
{
 if(dp->words) deletebuffer(&dp->words);
 if(dp->index) deletebuffer(&dp->index);
 dp->nowords=0;
 dp->noindex=0;
}



/* initialise dictionary structure */

void createdc(dict * dp)
{
 createbuffer(&dp->words);
 createbuffer(&dp->index);
 dp->nowords=0;
 dp->noindex=0;
}



FILE * dopen(char * name,char * mode)
{
 char string[256];
 strcpy(string,"<CrossStarDictionary$Path>.Dictionary.");
 strcat(string,name);
 return(fopen(string,mode));
}


/* lo level load dictionary into dictionary structure */

int loaddc(char * name,dict * dp)
{
 FILE * fp;
 dheader dh;
 int     code;

 fp=dopen(name,"rb");
 if(!fp) return(0);
 trashdc(dp);

 fread(&dh,sizeof(dheader),1,fp);
 fread(&dp->nowords,4,1,fp);
 fread(&dp->noindex,4,1,fp);

 code=loadbuffer(&dp->words,fp);

 if(!code) code=loadbuffer(&dp->index,fp);
 fclose(fp);

 if(code)
 {
  dp->nowords=dp->noindex=0;
  return(0);
 }
 else 
  return(1);
}


/* lo level save dictionary strcuture */

int savedc(char * name,dict * dp)
{
 FILE * fp;
 dheader dh;
 int     i;

 for(i=0;i<sizeof(dheader);i++) *(((char*)(&dh))+i)=0;

 strcpy(dh.name,"CrossStar Dictionary");
 strcpy(dh.mark,"0.00");
 strcpy(dh.copy,"(18-Jun-1990)");

 fp=dopen(name,"wb");
 if(!fp) return(0);

 fwrite(&dh,sizeof(dheader),1,fp);
 fwrite(&dp->nowords,4,1,fp);
 fwrite(&dp->noindex,4,1,fp);
 savebuffer(dp->words,fp);
 savebuffer(dp->index,fp);
 fclose(fp);
 return(1);
}

/*

void dctest(void)
{
 index indi;
 int   woffset;
 int   wordn;

 while(1)
 {
  printf("\ninput:");
  scanf("%d %d",&woffset,&wordn);

  SETWOFF(&indi,woffset);
  SETWORDN(&indi,wordn);

  printf("woffset=%d wordn=%d\n",woffset,wordn);

  woffset=WOFF(&indi);
  wordn=WORDN(&indi);

  printf("woffset=%d wordn=%d\n",woffset,wordn);

  SETWOFF(&indi,WOFF(&indi)+8);
  SETWORDN(&indi,WORDN(&indi)+8);


  woffset=WOFF(&indi);
  wordn=WORDN(&indi);


  printf("woffset=%d wordn=%d\n",woffset,wordn);

  printf("indexp.woffset=%d indexp.wordn=%d indi.extra=%x\n",
             indi.woffset,indi.wordn,indi.extra);


 }

}
*/




